"""
游戏控制模块 - 负责发送操作指令控制魔兽争霸3游戏

该模块使用PyAutoGUI/PyDirectInput库发送鼠标和键盘指令，
控制游戏中的各种操作，如选择单位、移动、攻击等。
"""

import pyautogui
import pydirectinput
import time
from typing import Tuple, Optional, Union
import numpy as np


class GameController:
    """
    游戏控制器类 - 控制魔兽争霸3游戏操作
    
    该类负责：
    1. 发送鼠标指令（点击、拖拽等）
    2. 发送键盘指令（快捷键等）
    3. 执行游戏内特定操作（建造、训练、攻击等）
    """
    
    def __init__(self, game_window_region: Tuple[int, int, int, int] = (0, 0, 1920, 1080)):
        """
        初始化游戏控制器
        
        Args:
            game_window_region: 游戏窗口区域 (x, y, width, height)
        """
        # 游戏窗口区域
        self.game_window_region = game_window_region
        
        # 设置PyAutoGUI延迟，避免操作过快
        pyautogui.PAUSE = 0.1
        pyautogui.FAILSAFE = True
        
        # 设置PyDirectInput延迟
        pydirectinput.PAUSE = 0.05
        
        print("游戏控制器初始化完成")

    def _clamp_point(self, x: int, y: int) -> Tuple[int, int]:
        """
        将坐标限制在游戏窗口区域内，避免越界操作
        """
        wx, wy, w, h = self.game_window_region
        cx = max(wx, min(wx + w - 1, x))
        cy = max(wy, min(wy + h - 1, y))
        return cx, cy
    
    def move_mouse(self, x: int, y: int, duration: float = 0.1) -> None:
        """
        移动鼠标到指定位置
        
        Args:
            x: X坐标
            y: Y坐标
            duration: 移动持续时间
        """
        try:
            x, y = self._clamp_point(x, y)
            pydirectinput.moveTo(x, y, duration=duration)
        except Exception as e:
            print(f"鼠标移动失败: {e}")
    
    def click(self, x: int, y: int, button: str = 'left', clicks: int = 1) -> None:
        """
        在指定位置点击鼠标
        
        Args:
            x: X坐标
            y: Y坐标
            button: 鼠标按钮 ('left', 'right', 'middle')
            clicks: 点击次数
        """
        try:
            x, y = self._clamp_point(x, y)
            pydirectinput.click(x, y, button=button, clicks=clicks)
        except Exception as e:
            print(f"鼠标点击失败: {e}")
    
    def drag_mouse(self, start_x: int, start_y: int, end_x: int, end_y: int, 
                   duration: float = 0.5, button: str = 'left') -> None:
        """
        拖拽鼠标
        
        Args:
            start_x: 起始X坐标
            start_y: 起始Y坐标
            end_x: 结束X坐标
            end_y: 结束Y坐标
            duration: 拖拽持续时间
            button: 拖拽按钮
        """
        try:
            start_x, start_y = self._clamp_point(start_x, start_y)
            end_x, end_y = self._clamp_point(end_x, end_y)
            pydirectinput.drag(start_x, start_y, end_x, end_y, 
                              duration=duration, button=button)
        except Exception as e:
            print(f"鼠标拖拽失败: {e}")
    
    def press_key(self, key: str, presses: int = 1, interval: float = 0.1) -> None:
        """
        按下指定键
        
        Args:
            key: 按键名称
            presses: 按压次数
            interval: 按压间隔
        """
        try:
            pydirectinput.press(key, presses=presses, interval=interval)
        except Exception as e:
            print(f"按键按下失败: {e}")
    
    def hotkey(self, *keys: str) -> None:
        """
        同时按下多个键（热键）
        
        Args:
            *keys: 按键组合
        """
        try:
            pydirectinput.hotkey(*keys)
        except Exception as e:
            print(f"热键按下失败: {e}")
    
    def select_units(self, positions: list) -> None:
        """
        选择单位（框选多个单位）
        
        Args:
            positions: 单位位置列表 [(x1, y1), (x2, y2), ...]
        """
        if len(positions) == 0:
            return
        
        try:
            # 如果只有一个位置，则直接点击选择
            if len(positions) == 1:
                self.click(positions[0][0], positions[0][1])
                return
            
            # 如果有多个位置，则使用框选
            # 先移动到第一个位置
            start_x, start_y = positions[0]
            self.move_mouse(start_x, start_y)
            
            # 按住左键
            pydirectinput.mouseDown(button='left')
            
            # 移动到对角位置
            end_x, end_y = positions[-1]
            pydirectinput.moveTo(end_x, end_y, duration=0.3)
            
            # 松开左键
            pydirectinput.mouseUp(button='left')
        except Exception as e:
            print(f"选择单位失败: {e}")
    
    def move_units(self, target_x: int, target_y: int) -> None:
        """
        移动选中的单位到目标位置
        
        Args:
            target_x: 目标X坐标
            target_y: 目标Y坐标
        """
        try:
            # 右键点击目标位置移动单位
            self.click(target_x, target_y, button='right')
        except Exception as e:
            print(f"移动单位失败: {e}")
    
    def attack_move(self, target_x: int, target_y: int) -> None:
        """
        攻击移动到目标位置（带攻击的移动）
        
        Args:
            target_x: 目标X坐标
            target_y: 目标Y坐标
        """
        try:
            # 按'A'键进入攻击移动模式
            self.press_key('a')
            # 点击目标位置
            self.click(target_x, target_y)
        except Exception as e:
            print(f"攻击移动失败: {e}")
    
    def build_structure(self, structure_key: str, x: int, y: int) -> None:
        """
        建造建筑
        
        Args:
            structure_key: 建筑对应的快捷键
            x: 建造位置X坐标
            y: 建造位置Y坐标
        """
        try:
            # 按下建筑快捷键
            self.press_key(structure_key)
            # 点击建造位置
            self.click(x, y)
        except Exception as e:
            print(f"建造建筑失败: {e}")
    
    def train_unit(self, unit_hotkey: str) -> None:
        """
        训练单位
        
        Args:
            unit_hotkey: 单位对应的快捷键
        """
        try:
            # 按下单位快捷键
            self.press_key(unit_hotkey)
        except Exception as e:
            print(f"训练单位失败: {e}")
    
    def cast_spell(self, spell_key: str, target_x: int = None, target_y: int = None) -> None:
        """
        施放技能
        
        Args:
            spell_key: 技能对应的快捷键
            target_x: 目标X坐标（可选）
            target_y: 目标Y坐标（可选）
        """
        try:
            # 按下技能快捷键
            self.press_key(spell_key)
            
            # 如果指定了目标位置，则点击目标
            if target_x is not None and target_y is not None:
                self.click(target_x, target_y)
        except Exception as e:
            print(f"施放技能失败: {e}")


# 使用示例
if __name__ == "__main__":
    # 创建游戏控制器实例
    controller = GameController()
    
    # 示例：选择单位并移动
    # controller.select_units([(100, 100), (200, 200)])
    # controller.move_units(500, 500)
    
    print("游戏控制器模块测试完成")
